package highLight;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.search.highlight.*;
import org.apache.lucene.search.matchhighlight.FieldValueHighlighters;
import org.apache.lucene.search.matchhighlight.MatchHighlighter;
import org.apache.lucene.search.matchhighlight.PassageFormatter;
import org.apache.lucene.store.MMapDirectory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.JRE;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;

import static org.apache.lucene.tests.util.LuceneTestCase.newStringField;

public class HighLightDemo2 {
    MMapDirectory mMapDirectory = null;
    IndexWriter indexWriter = null;
    WhitespaceAnalyzer whitespaceAnalyzer =null;
    String uri = "F:\\integration\\search\\lucene-data\\highlight";

//    @AfterEach
    public void tearDown() throws IOException {

        Files.walkFileTree(Paths.get(uri), new SimpleFileVisitor<Path>() {
          @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
              throws IOException
            {
                Files.delete(file);
                return FileVisitResult.CONTINUE;
            }
         @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException e)
              throws IOException
            {
                if (e == null) {
                    Files.delete(dir);
                    return FileVisitResult.CONTINUE;
                } else {
                    // directory iteration failed
                    throw e;
                }
            }
        });
    }
    @BeforeEach
    public void setUp() {
        try {
            mMapDirectory = new MMapDirectory(Paths.get(uri));
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig();
            indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
            whitespaceAnalyzer = new WhitespaceAnalyzer();
            indexWriter = new IndexWriter(mMapDirectory, new IndexWriterConfig(whitespaceAnalyzer));

        } catch (IOException e) {
            throw new RuntimeException("mmap failed");
        }

    }

    private static final String FLD_ID = "id";

    @Test
    public void indexAndSearch() throws IOException, InvalidTokenOffsetsException, ParseException {
        String[] docs =
                new String[]{
                        "One million (i.e., 1,000,000) one thousand thousand. This is the natural number (or counting number) followed by 999,999 and preceded by 1,000,001", // 0
                        "The word “million” is derived from the early Italian million (milione in modern Italian), from mille", // 1
                        "thousand”, plus the augmentative suffix -one. It is abbreviated as m.",
                        "2 million",
                        "3 million",
                        "4 million",
                        "5 million",
                        "6 million",
                        "7 million",
                        "8 million",
                        "9 million",
                };
        for (int i = 0; i < docs.length; i++) {
            Document doc = new Document();
            doc.add(newStringField(FLD_ID, "" + i, Field.Store.YES));
            doc.add(newStringField("notv", docs[i], Field.Store.YES));
            doc.add(newStringField("tv", docs[i], Field.Store.YES));
            indexWriter.addDocument(doc);
        }
        indexWriter.close();;
    }

    @Test
    public void verify() throws ParseException, IOException, InvalidTokenOffsetsException {

        DirectoryReader reader = DirectoryReader.open(indexWriter);
        IndexSearcher searcher = new IndexSearcher(reader);
    // ** importance ** use complete match
        QueryParser parser = new QueryParser("notv", whitespaceAnalyzer);
        parser.setSplitOnWhitespace(true);
        parser.setAllowLeadingWildcard(true);
        Query query = parser.parse("*million");

        TopDocs hits = searcher.search(query, 10);
// have no results , QueryParser have problems.
        if (hits.scoreDocs.length==0)return;

        SimpleHTMLFormatter htmlFormatter = new SimpleHTMLFormatter();
        Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
        for (int i = 0; i < hits.scoreDocs.length; i++) {
            int id = hits.scoreDocs[i].doc;
            Document doc = searcher.doc(id);
            String text = doc.get("notv");
            TokenStream tokenStream = TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "notv", whitespaceAnalyzer);
            TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, text, false, 10);//highlighter.getBestFragments(tokenStream, text, 3, "...");
            for (int j = 0; j < frag.length; j++) {
                if ((frag[j] != null) && (frag[j].getScore() > 0)) {
                    System.out.println((frag[j].toString()));
                }
            }
            //Term vector
            text = doc.get("tv");
            tokenStream = TokenSources.getAnyTokenStream(searcher.getIndexReader(), hits.scoreDocs[i].doc, "tv", whitespaceAnalyzer);
            frag = highlighter.getBestTextFragments(tokenStream, text, false, 10);
            for (int j = 0; j < frag.length; j++) {
                if ((frag[j] != null) && (frag[j].getScore() > 0)) {
                    System.out.println((frag[j].toString()));
                }
            }
            System.out.println("-------------");
        }

        reader.close();;


    }
}